查看原文
其他

数据仓库中的增量&全量

点击上方蓝色字体,选择“设为星标”

回复”资源“获取更多惊喜

数据仓库的两个重要的概念是:

  • 进入仓库的数据不可变

  • 记录数据的变化历史

如何理解呢?不可变,意味着进到仓库的数据就类似归档了。原则上,不能对仓库里面的数据进行修改;如果随意的对仓库里面的数据进行修改,这个“仓库”就和交易系统没区别了,无法起到正确反映业务过程的作用。此外,适合于数据仓库的存储服务,如早年Oracle和DB2都有针对数据仓库的Data Warehouse产品,以及Hadoop体系的一系列组件,都是针对“批量插入,无更改或少量更改”而专门设计的,所以才能达到查询效率的最优化。也因此产生了OLTP系统和OLAP系统的两大模式。

因此,“数据不可变”这是一个基准原则。

但是业务系统(OLTP)的数据其实是持续变化的,不但有新增的,而且也会修改原有的记录。利用数据仓库数据不可变的特性,可以粗暴的认为每天把一份业务系统数据的快照保存到仓库里面,这样实际上最完整的保存了业务每天变化的历史。但这样做数据量会非常庞大,无数的冗余数据不断的进入仓库——毕竟一般情况相比历史数据而言,每天的变更总是少数的。

这时候,我们就要分析一下数据的变化。一般来说,我们按照数据变化的频率来划分,会有几种可能:

  • 纯新增:比如银行的交易流水,记录对象就是交易本身,交易每时每刻都在发生,不断的插入新的交易记录。而且交易记录一旦产生,其内容不会再改变。如果某条交易有问题,需要通过冲正、撤销以及反向交易等手段处理,相当于又增加一条交易记录。

  • 频繁变更:比如银行系统的账户表,由于账务交易的频繁发生,导致账户余额也不断变化。余额是账户的一个属性,意味着账户表会一直被修改。对于活跃客户,基本上账户表每天都变化。

  • 缓慢变化:比如用户的住址、电话等,并不会经常,但一定会改变。对于单个客户而言,这种改变可能很不常见,但对于客户信息表的全集而言,则需要认为可能每天都有少部分记录发生变化。这里带来一个问题就是对于信息的有效期段,比如某客户在一个时间段用A住址,下一个时间段换成B住址。

另外,还有一种变化更加少的。比如银行的分支机构、产品等,类似业务参数的数据。首先明确,这种数据一定会变化,而且这种数据的变化影响非常大,尤其对于统计维度。其次,这种变化确实不会太多。而且,这种数据一般来说数据量都很小(相比业务数据)。

频繁变更的数据的另一个例子是电商中的订单表。和上面说的账户余额表有点类似。订单发生之后,随着订单状态变化,订单记录会被修改,比如创建、支付、发货、签收等状态。如果数仓一天采集一次数据,则一天之内的订单变化过程会丢失;跨天完成的订单则会导致修改已经进入仓库的订单数据。如果要在数仓记录订单的变化状态,一是实时采集,二是使用订单状态变更流水表。订单表的一个特点是,一般经过一段时间之后,就不会再变化,比如一般一个月(过了签收和退换期)之前的数据,基本都不会变化了。

这里插个题外话,一般交易量巨大的交易系统,如电商,都会把变更操作改成插入操作。比如刚刚说的,用订单状态变更流水表来记录订单的状态。状态改变的时候,插入最新的状态,而不去修改订单表。但这样的设计会带来查询的复杂,很多系统并不会这样做。

了解了数据是如何变化之后,可以设计相应的策略,把变化的业务数据放到“不可变”的数据仓库中了。

根据数据不同有几种方式:

纯增量

类似交易流水、交易日志、登记簿之类的数据,数据发生的时候,就有明确的时间戳,并且数据发生之后不会改变的,比如上面说的账户交易流水表,记录产生之后不可变更。可以直接根据时间戳把当天的数据挑选出来,这批数据直接插入全量表,每日追加数据即可。

一般会单独增加一个日期字段表示数据什么时候进来的。

对比增量

类似账户表、用户信息表之类主数据信息表或者状态表,在交易系统中往往只会记录最新状态而不会记录变化时间。当然,也有系统保留操作日志,记录变更情况。

对于前者,需要我们自己把最新数据和仓库里的数据做一个对比,找出被变更过的数据。

对于后者,如果源系统做了对比,自行找出了增量,到了数据仓库平台不需要做增量对比。但需要考虑删除的数据是否标注出来了,虽然直接物理删除的情况不多,但还是需要考虑的。

数据的变更包括增加、修改、删除。这里的删除指的是真正的物理删除。给数据做标记逻辑删除的需要根据具体情况分析,比如业务含义上确实是删除的,就按删除处理。但这种方式慎用。良好的设计中,这种情况应该很少。比如,账户注销了,我们不要物理上删除这个账户记录,而应该增加一个业务状态叫“注销”。按照数据变更处理。

这里就出现了“数据有效期”的处理了。A记录在D1日进入系统,在D2日被修改。在仓库的记录情况则是如下两条记录:

记录一R1:A记录内容,时间戳:D1,状态:新增;
记录二R2:A记录的最新内容,时间戳:D2,状态:更新;

R1的的有效期是D1到D2(不包含D2),R2的有效期是D2至今。对被删除的数据,可以把最新的数据复制一份,增加当前日期做时间戳,状态为“删除”,然后插入到仓库表中。即:

记录三R3:A记录的最新内容,时间戳:D3,状态:删除;

至于比对的方式,没什么可取巧的地方,拿着最新数据逐条对比仓库中的最新日期的那一份数据就好。

仓库里面的记录有效期只有开始日期而没有结束日期,在使用上,会带来不便。比如找出当前有效的记录就得找最大的开始日期。因此,在上述机制基础上有两种优化或变形:

  • 事先生成快照表。在每天处理完数据之后,可以针对这种表生成一个快照表,该表只记录最新状态,不记录变更历史。增量对比通过快照表来找,而不在全量历史中处理。当然,如果快照表的数据量本身也很大,就需要好好衡量得失了。

  • 增加有效截止日期。但这样导致需要更新仓库里面的数据。这就违背不可更新的原则。这就需要配合仓库存储工具(数据库、HIVE等),利用分区机制(一般一个分区是一个独立文件),删掉变更影响的分区然后重建。大致流程是创建一个临时表,把需要更新的数据都放进去,然后删除仓库表对应的分区,再把新的数据插回去(比如HIVE的INSERT OVERWRITE)。这种方式也叫“拉链表”。

不管哪种方式,永远要切记的是:

不要对仓库里的表做更新(update)操作!

空间和时间的对比是软件届是永恒的矛盾话题。在这里也是一样。

全量处理

对于类似机构、产品/产品类型等各种“分类”数据,或者一些业务参数,往往数据量不大,几十条,几百条这样。而且交易系统中并不关心这些数据是否变化,现状是什么样就直接用即可。但这种数据在仓库里面,往往是重要的统计维度,而且还会有如下几种不同的汇总需求:

  1. 以前的数据按照以前的分类汇总,分类变更之后的数据按照新的汇总

  2. 现在的数据用以前的分类进行汇总

  3. 以前的数据用现在的分类进行汇总

第一种是常规需求。后两种则也会碰到,尤其是想对比一下变化前后有什么区别。

但无论如何,从进入仓库的角度,全量数据比较简单,把每天的数据加上时间戳之后全量放入仓库即可。也就是每天一份全量数据,使用的时候根据所需要的时间点来选择。


Flink结合Kafka实时写入Iceberg实践笔记


数据仓库构建方法论和简单实践

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存